package com.example.a_java.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.a_java.dto.ContractSignDTO;
import com.example.a_java.entity.ContractAttachment;
import com.example.a_java.entity.ContractSignatory;
import com.example.a_java.entity.LoanContract;
import com.example.a_java.mapper.ContractAttachmentMapper;
import com.example.a_java.mapper.ContractSignatoryMapper;
import com.example.a_java.mapper.LoanContractMapper;
import com.example.a_java.service.LoanContractService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

/**
 * 合同信息Service实现类
 */
@Service
public class LoanContractServiceImpl extends ServiceImpl<LoanContractMapper, LoanContract> implements LoanContractService {
    
    private static final Logger logger = LoggerFactory.getLogger(LoanContractServiceImpl.class);
    
    @Autowired
    private ContractSignatoryMapper signatoryMapper;
    
    @Autowired
    private ContractAttachmentMapper attachmentMapper;
    
    @Value("${file.upload.path:/upload}")
    private String uploadPath;
    
    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean generateContract(LoanContract contract) {
        try {
            logger.info("开始生成贷款合同");
            
            // 1. 生成合同编号
            String contractNo = "HT" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
            contract.setContractNo(contractNo);
            
            // 2. 设置合同状态为待签署
            contract.setContractStatus(10);
            
            // 3. 设置创建时间
            LocalDateTime now = LocalDateTime.now();
            contract.setCreateTime(now);
            contract.setUpdateTime(now);
            
            // 4. 设置必填字段默认值（如果为空）
            
            // 申请ID
            if (contract.getApplyId() == null) {
                contract.setApplyId(1L);
            }
            
            // 客户ID
            if (contract.getCustId() == null) {
                contract.setCustId(1L);
            }
            
            // 贷款金额
            if (contract.getLoanAmount() == null) {
                contract.setLoanAmount(new BigDecimal("10000.00"));
            }
            
            // 贷款期限
            if (contract.getLoanTerm() == null) {
                contract.setLoanTerm(12); // 默认12个月
            }
            
            // 贷款用途 - 这个是新添加的默认值
            if (contract.getLoanPurpose() == null || contract.getLoanPurpose().trim().isEmpty()) {
                contract.setLoanPurpose("个人消费"); // 设置默认贷款用途
            }
            
            // 还款方式
            if (contract.getRepayMethod() == null) {
                contract.setRepayMethod(1); // 默认等额本息
            }
            
            // 担保方式
            if (contract.getGuarMethod() == null) {
                contract.setGuarMethod(1); // 默认信用
            }
            
            // 年化利率
            if (contract.getInterestRate() == null) {
                contract.setInterestRate(new BigDecimal("4.35")); // 默认LPR基准利率
            }
            
            // 签约日期
            if (contract.getSignDate() == null) {
                contract.setSignDate(LocalDate.now());
            }
            
            // 合同类型
            if (contract.getContractType() == null || contract.getContractType().trim().isEmpty()) {
                contract.setContractType("loan"); // 默认贷款合同
            }
            
            // 开始日期和结束日期
            if (contract.getStartDate() == null) {
                contract.setStartDate(LocalDate.now());
            }
            
            if (contract.getEndDate() == null && contract.getLoanTerm() != null && contract.getStartDate() != null) {
                // 根据贷款期限计算结束日期
                contract.setEndDate(contract.getStartDate().plusMonths(contract.getLoanTerm()));
            }
            
            logger.info("贷款合同数据准备完成，准备保存到数据库");
            boolean result = save(contract);
            logger.info("贷款合同保存结果: {}", result);
            return result;
        } catch (Exception e) {
            logger.error("生成贷款合同异常", e);
            throw e; // 由于有@Transactional注解，这里抛出异常会触发回滚
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean signContract(ContractSignDTO signDTO) {
        try {
            logger.info("开始处理合同签署请求 合同ID: {}", signDTO.getContractId());
            
            // 1. 检查合同是否存在
            LoanContract contract = getById(signDTO.getContractId());
            if (contract == null) {
                logger.error("合同不存在, 合同ID: {}", signDTO.getContractId());
                throw new RuntimeException("合同不存在");
            }
            
            // 2. 检查合同状态是否允许签署
            if (contract.getContractStatus() != 10) {
                logger.error("当前合同状态不允许签署, 合同ID: {}, 当前状态 {}", 
                        signDTO.getContractId(), contract.getContractStatus());
                throw new RuntimeException("当前合同状态不允许签署");
            }
            
            // 3. 解析签署时间
            LocalDateTime signTime;
            try {
                signTime = LocalDateTime.parse(signDTO.getSignTime(), DATETIME_FORMATTER);
            } catch (Exception e) {
                logger.error("签署时间格式不正确 {}", signDTO.getSignTime(), e);
                throw new RuntimeException("签署时间格式不正确，正确格式为：yyyy-MM-dd HH:mm:ss");
            }
            
            // 4. 更新合同状态为已签署
            LoanContract updateContract = new LoanContract();
            updateContract.setContractId(signDTO.getContractId());
            updateContract.setContractStatus(20); // 已签署
            updateContract.setSignTime(signTime);
            updateContract.setRemark(signDTO.getRemark());
            
            boolean updated = updateById(updateContract);
            if (!updated) {
                logger.error("更新合同状态失败 合同ID: {}", signDTO.getContractId());
                return false;
            }
            
            // 5. 更新签署方状态
            List<ContractSignatory> signatories = signatoryMapper.selectList(
                    new LambdaQueryWrapper<ContractSignatory>()
                            .eq(ContractSignatory::getContractId, signDTO.getContractId())
                            .eq(ContractSignatory::getIsDeleted, 0)
            );
            
            for (ContractSignatory signatory : signatories) {
                signatory.setSignStatus("signed");
                signatory.setSignTime(signTime);
                signatory.setSignMethod(signDTO.getMethod());
                signatoryMapper.updateById(signatory);
            }
            
            // 6. 保存附件（如果有）
            if (signDTO.getAttachments() != null && !signDTO.getAttachments().isEmpty()) {
                saveAttachments(signDTO.getContractId(), signDTO.getAttachments());
            }
            
            logger.info("合同签署处理完成, 合同ID: {}", signDTO.getContractId());
            return true;
        } catch (RuntimeException e) {
            // 已经包含了自定义错误信息的异常，直接抛出
            throw e;
        } catch (Exception e) {
            logger.error("合同签署处理异常", e);
            throw new RuntimeException("合同签署处理异常: " + e.getMessage());
        }
    }
    
    /**
     * 保存合同附件
     * 
     * @param contractId 合同ID
     * @param attachments 附件列表
     */
    private void saveAttachments(Long contractId, List<ContractSignDTO.AttachmentDTO> attachments) {
        if (attachments == null || attachments.isEmpty()) {
            return;
        }
        
        // 确保上传目录存在
        String contractDir = uploadPath + "/contract/" + contractId;
        File dir = new File(contractDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        
        for (ContractSignDTO.AttachmentDTO attachment : attachments) {
            try {
                // 生成文件名
                String fileName = attachment.getName();
                String fileType = getFileType(fileName);
                String filePath = contractDir + "/" + System.currentTimeMillis() + "_" + fileName;
                
                // 解码Base64并保存文件
                byte[] fileContent = Base64.getDecoder().decode(attachment.getContent());
                Files.write(Paths.get(filePath), fileContent);
                
                // 保存附件记录
                ContractAttachment contractAttachment = new ContractAttachment();
                contractAttachment.setContractId(contractId);
                contractAttachment.setFileName(fileName);
                contractAttachment.setFilePath(filePath);
                contractAttachment.setFileType(fileType);
                contractAttachment.setFileSize((long) fileContent.length);
                contractAttachment.setUploadTime(LocalDateTime.now());
                
                attachmentMapper.insert(contractAttachment);
                
            } catch (IOException e) {
                logger.error("保存合同附件失败", e);
                throw new RuntimeException("保存合同附件失败: " + e.getMessage());
            }
        }
    }
    
    /**
     * 根据文件名获取文件类型
     * 
     * @param fileName 文件名
     * @return 文件类型
     */
    private String getFileType(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "application/octet-stream";
        }
        
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        
        switch (extension) {
            case "pdf":
                return "application/pdf";
            case "jpg":
            case "jpeg":
                return "image/jpeg";
            case "png":
                return "image/png";
            case "doc":
                return "application/msword";
            case "docx":
                return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            default:
                return "application/octet-stream";
        }
    }
} 
